'''
 * CaRComp Execution Environment
 * 
 * Copyright (C) 2011 Taylor L. Riche
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
'''

from carcomp.framework import io_component, component
import select, socket

class NetReaderComponent(io_component.IOComponent):
    '''
    classdocs
    '''

    def __init__(self, name, dir_instance):
        '''
        Constructor
        '''
        io_component.IOComponent.__init__(self, name)
        self.__listen_port__ = dir_instance.listen_port(name)
        self.__listen_socket__ = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.__listen_socket__.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.__listen_socket__.bind((dir_instance.address(name), self.__listen_port__)) 
        self.__listen_socket__.listen(1024)
        self.__listen_socket__.setblocking(False)
        self.__open_socks__ = {}
        self.time_to_stop = False
        self.__inputs__ = [self.__listen_socket__]
        
    def handle_input_stream(self, msg):
        
        try:
            socket_sets = select.select(self.__inputs__, [], [], 1)
            input_ready = socket_sets[0]
        except select.error:
            return
        except socket.error:
            return
        
        for s in input_ready:
            if s == self.__listen_socket__:
                # create new connection for reading data
                remote_sock, remote_addr = self.__listen_socket__.accept()
                self.__inputs__.append(remote_sock)
                self.__open_socks__[remote_sock] = remote_addr
            else:
                # data socket
                try:
                    data = s.recv(1024)
                    if(data):
                        # other side has sent data
                        self.send_out('out', data.decode('utf-8'))
                    else:
                        # other side has ended communication
                        s.close()
                        self.__inputs__.remove(s)
                        self.__open_socks__.pop(s)
                except socket.error:
                    # on an error just cleanup
                    s.close()
                    self.__inputs__.remove(s)
                    self.__open_socks__.pop(s)
        raise component.RestartComponent 
    
    def cleanup(self):
        '''Close all open sockets'''
        for sock in self.__inputs__:
            sock.close()
    
    
        